package com.gwz.cardserver.service;

import com.alibaba.fastjson.JSON;
import com.gwz.cardserver.consts.FightCodeConst;
import com.gwz.cardserver.consts.SocketConst;
import com.gwz.cardserver.dto.ReqBase;
import com.gwz.cardserver.dto.ResBase;
import com.gwz.cardserver.dto.fight.*;
import com.gwz.cardserver.entity.Account;
import com.gwz.cardserver.global.FightCache;
import com.gwz.cardserver.global.GlobalCache;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.List;

@Service
public class FightService {
    @Autowired
    private FightCache fightCache;
    @Autowired
    private GlobalCache globalCache;
    @Autowired
    private AccountService accountService;

    /**
     * 不出
     *
     * @param ctx
     * @param reqBase
     */
    public synchronized void pass(ChannelHandlerContext ctx, ReqBase reqBase) {
        Assert.isTrue(accountService.isOnline(ctx), ResBase.fall(reqBase, "玩家不在线"));
        String userId = globalCache.getUserIdBYChannel(ctx);
        FightRoom fightRoom = fightCache.getRoomByUserId(userId);
        if (fightRoom.roundModel.getBiggestUid() == userId) {
            ctx.writeAndFlush(ResBase.success(reqBase, -1));
        } else {
            ctx.writeAndFlush(ResBase.success(reqBase, 0));
            turn(fightRoom);
        }

    }

    /**
     * 出牌处理
     *
     * @param ctx
     * @param reqBase
     */
    public synchronized void deal(ChannelHandlerContext ctx, ReqBase reqBase) {
        DealDto dto = JSON.parseObject(reqBase.getMessage(), DealDto.class);
        Assert.isTrue(accountService.isOnline(ctx), ResBase.fall(reqBase, "玩家不在线"));
        String userId = globalCache.getUserIdBYChannel(ctx);
        FightRoom fightRoom = fightCache.getRoomByUserId(userId);
        if (fightRoom.getLeaveUids().contains(userId)) {
            turn(fightRoom);
        }
        boolean canDeal = fightRoom.deadCard(dto.getType(), dto.getWeight(), dto.getLength(), userId, dto.getSelectCardList());
        if (canDeal == false) {
            ctx.writeAndFlush(ResBase.success(reqBase, -1));
            return;
        } else {
            // 发送出牌成功
            ctx.writeAndFlush(ResBase.success(reqBase, 0));
            ResBase resBase = new ResBase();
            resBase.setResCode(200);
            resBase.setCode(SocketConst.FIGHT);
            resBase.setSubCode(FightCodeConst.DEAL_BRO);
            resBase.setResult(dto);
            brocast(resBase, null, fightRoom);

            // 检测剩余手牌
            List<CardDto> cardList = fightRoom.getPlayerModel(userId).getCardList();
            if (cardList.size() == 0) {
                gameOver(userId, fightRoom);
            } else {
                turn(fightRoom);
            }
        }
    }

    /**
     * 游戏结束
     *
     * @param userId
     * @param room
     */
    private void gameOver(String userId, FightRoom room) {
        int winIdentity = room.getPlayerIdentity(userId);
        // 胜利玩家处理
        List<String> winUids = room.getSameIdentityUids(winIdentity);
        int winBeen = room.getMultiple() * 1000;
        for (int i = 0; i < winUids.size(); i++) {
            Account account = accountService.getById(winUids.get(i));
            account.setWinCount(account.getWinCount() + 1);
            account.setBeen(account.getBeen() + winBeen);
            account.setExp(account.getExp() + 100);
            accountService.updateById(account);
        }
        // 失败玩家处理
        List<String> loseUids = room.getNotSameIdentityUids(winIdentity);
        for (int i = 0; i < loseUids.size(); i++) {
            Account account = accountService.getById(loseUids.get(i));
            account.setLoseCount(account.getLoseCount() + 1);
            account.setBeen(account.getBeen() - winBeen);
            account.setExp(account.getExp() + 10);
            accountService.updateById(account);
        }

        // 逃跑玩家处理
        for (int i = 0; i < room.getLeaveUids().size(); i++) {
            Account account = accountService.getById(room.getLeaveUids().get(i));
            account.setRunCount(account.getRunCount() + 1);
            account.setBeen(account.getBeen() - (winBeen * 3));
            accountService.updateById(account);
        }

        OverDto overDto = new OverDto();
        overDto.setWinIdentity(overDto.getWinIdentity());
        overDto.setWinUidList(winUids);
        overDto.setBeenCount(winBeen);

        ResBase resBase = new ResBase();
        resBase.setResult(overDto);
        resBase.setResCode(200);
        resBase.setCode(SocketConst.FIGHT);
        resBase.setSubCode(FightCodeConst.OVER_BRO);
        brocast(resBase, null, room);
        fightCache.destory(room);

    }


    /**
     * 开始战斗
     *
     * @param uids
     */
    public synchronized void startFight(List<String> uids) throws InterruptedException {
        FightRoom room = fightCache.create(uids);
        room.initPlayerCards();
        room.sort(true);
        for (String uid : uids) {
            ChannelHandlerContext context = globalCache.getChannelByUserId(uid);
            List<CardDto> userCards = room.getUserCards(uid);
            ResBase resBase = new ResBase();
            resBase.setCode(SocketConst.FIGHT);
            resBase.setSubCode(FightCodeConst.GET_CARD_SRES);
            resBase.setResCode(200);
            resBase.setResult(userCards);
            context.write(JSON.toJSONString(resBase));
            context.flush();
        }
        Thread.sleep(1000);
        String firstUserId = room.getFirstUid();
        ResBase resBase = new ResBase();
        resBase.setCode(SocketConst.FIGHT);
        resBase.setSubCode(FightCodeConst.TURN_GRAB_BRO);
        resBase.setResCode(200);
        resBase.setResult(firstUserId);
        brocast(resBase, null, room);
    }


    /**
     * 抢地主的处理
     *
     * @param ctx
     * @param reqBase
     */
    public synchronized void grabLandlord(ChannelHandlerContext ctx, ReqBase reqBase) {
        boolean result = Boolean.parseBoolean(reqBase.getMessage());
        String userId = globalCache.getUserIdBYChannel(ctx);
        Assert.isTrue(accountService.isOnline(userId), ResBase.fall(reqBase, "玩家不在线"));
        FightRoom room = fightCache.getRoomByUserId(userId);
        // 抢地主
        if (result) {
            room.setLandlord(userId);
            GrabDto dto = GrabDto.builder().userId(userId).tableCardList(room.getTableCardList()).build();
            ResBase resBase = new ResBase();
            resBase.setCode(SocketConst.FIGHT);
            resBase.setSubCode(FightCodeConst.GRAB_LANDLOAD_BRO);
            resBase.setResCode(200);
            resBase.setResult(dto);
            brocast(resBase, null, room);
        } else {
            // 不抢
            String nextUid = room.getNextUid(userId);
            ResBase resBase = new ResBase();
            resBase.setCode(SocketConst.FIGHT);
            resBase.setSubCode(FightCodeConst.TURN_GRAB_BRO);
            resBase.setResCode(200);
            resBase.setResult(nextUid);
            brocast(resBase, null, room);
        }


    }

    /**
     * 转换出牌
     *
     * @param room
     */
    private void turn(FightRoom room) {
        String nextUid = room.turn();
        if (room.isOffline(nextUid) == true) {
            turn(room);
        } else {
            ChannelHandlerContext nextContext = globalCache.getChannelByUserId(nextUid);
            ResBase resBase = new ResBase();
            resBase.setResCode(200);
            resBase.setCode(SocketConst.FIGHT);
            resBase.setSubCode(FightCodeConst.TURN_DEAL_BRO);
            resBase.setResult(nextUid);
            nextContext.writeAndFlush(JSON.toJSONString(resBase));
        }
    }


    /**
     * 广播房间内的所有玩家信息
     */
    private void brocast(ResBase resBase, ChannelHandlerContext exChannel, FightRoom room) {

        for (PlayerDto player : room.getPlayers()) {
            // 玩家在线再进行发送
            if(accountService.isOnline(player.getUserId())){
                ChannelHandlerContext context = globalCache.getChannelByUserId(player.getUserId());
                if (context == exChannel)
                    continue;
                context.write(JSON.toJSONString(resBase));
                context.flush();
            }
        }
    }

    /**
     * 离开
     *
     * @param ctx
     */
    public synchronized void handlerRemoved(ChannelHandlerContext ctx) {
        if (!accountService.isOnline(ctx)) {
            return;
        }
        String userId = globalCache.getUserIdBYChannel(ctx);

        // 用户不在战斗房间
        if(fightCache.isFighting(userId) == false)
            return;

        FightRoom fightRoom = fightCache.getRoomByUserId(userId);
        fightRoom.getLeaveUids().add(userId);
        ResBase resBase = new ResBase();
        resBase.setResCode(200);
        resBase.setCode(SocketConst.FIGHT);
        resBase.setSubCode(FightCodeConst.LEAVE_BRO);
        resBase.setResult(userId);
        brocast(resBase, ctx, fightRoom);
        if (fightRoom.getLeaveUids().size() == 3) {
            // 所有人都离开了房间
            for (int i = 0; i < fightRoom.getLeaveUids().size(); i++) {
                Account account = accountService.getById(fightRoom.getLeaveUids().get(i));
                account.setRunCount(account.getRunCount() + 1);
                account.setBeen(account.getBeen() - (fightRoom.getMultiple() * 100 * 3));
                accountService.updateById(account);
            }
            fightCache.destory(fightRoom);
        }
    }
}
